grammar Cmm;

program: stmt+;

stmt    : declStmt
        | ifStmt
        | whileStmt
        |(assignStmt SEMI)
        | readStmt
        | writeStmt
        | stmtBlock
        | forStmt
        ;

declStmt: type deAs(COMMA deAs)* SEMI | type L_BRACKET INT R_BRACKET ID SEMI;

deAs: ID | ID ASSIGN MINUS? expr;

ifStmt: IF L_PAREN compare R_PAREN stmtBlock ( ELSE_IF L_PAREN compare R_PAREN stmtBlock)* (ELSE stmtBlock)*;

whileStmt: WHILE L_PAREN compare R_PAREN stmtBlock;

assignStmt: variable ASSIGN MINUS? expr;

readStmt: READ L_PAREN expr R_PAREN SEMI;

writeStmt: WRITE L_PAREN expr R_PAREN SEMI;

stmtBlock: L_BRACE stmt* R_BRACE;

forStmt : FOR L_PAREN((assignStmt SEMI)|declStmt) compare SEMI assignStmt R_PAREN stmtBlock;

type: T_INT | T_DOUBLE;

variable: ID | ID L_BRACKET (expr) R_BRACKET ;

number: INT| DOUBLE ;

compare :  UN_EQUAL compare | expr RELATION expr | L_PAREN compare R_PAREN ;

RELATION : BIGGER_THAN|LESS_THAN|NO_LESS|NO_MORE|EQUAL|UN_EQUAL;

expr    : expr1 expr2;
expr1   : expr4 expr3;
expr2   : (Plus|Minus) expr1 expr2
        |
        ;
expr3   : (Mul|Div|Mod) expr4 expr3
        |
        ;
expr4   : variable
        | number
        | L_PAREN expr R_PAREN
        ;


FOR : 'for';
IF : 'if';
ELSE : 'else';
ELSE_IF : 'else if';
WHILE :'while';
BREAK : 'break';
Continue : 'continue';

T_DOUBLE : 'double';
T_INT : 'int';
WRITE : 'write';
READ  : 'read';

L_PAREN : '(';
R_PAREN : ')';
L_BRACKET : '[';
R_BRACKET : ']';
L_BRACE : '{';
R_BRACE : '}';

NO_LESS: '>=';
NO_MORE: '<=';
EQUAL: '==';
UN_EQUAL:'!='|'<>';
BIGGER_THAN: '>';
LESS_THAN: '<';
LOG_NOT:'!';

LOG_OR:'||';
LOG_AND: '&&';
PLUS : '+';
MINUS : '-';
MUL : '*';
DIV : '/';
MOD : '%';
NOT : '!';
SEMI : ';';
COMMA : ',';
ASSIGN : '=';

//ESC:('\"'|'\\' [btnr"\\]) ;

ID : ID_LETTER (ID_LETTER | DIGIT)* ; // From C language
fragment ID_LETTER : [a-z]|[A-Z]|'_' ;
fragment DIGIT : [0-9] ;
INT: DIGIT+;
DOUBLE : DIGIT+ '.' DIGIT* ;

ESCAPE:  '\\' ['"?abfnrtv\\];
WS :   [ \t\r\n]+  -> skip;
NEW_LINE :   (   '\r' '\n'? |   '\n' ) -> skip;
B_COMMENT :   '/*' .*? '*/' -> skip;
L_COMMENT :  '//' .*? '\r'? '\n' -> skip ;








